package com.ra.pay.alipay;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.dom4j.DocumentException;
import org.springframework.stereotype.Service;

import com.espirit.eap.util.Functions;
import com.espirit.https.HttpClientManager;
import com.googlecode.cswish.struts.FreemarkerResult;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.Result;
import com.ra.landlord.BankCard;
import com.ra.landlord.LandlordUser;
import com.ra.landlord.Room;
import com.ra.order.BatchTransRecord;
import com.ra.order.OrderUtil;
import com.ra.order.PayOrder;
import com.ra.order.rental.BatchTransRentalRecord;
import com.ra.order.rental.RentalOrder;
import com.ra.pay.PaymentRecord;
import com.ra.util.RaConstant;

@Service
public class AlipayService {
	
	private static final Log logger = LogFactory.getLog(AlipayUtil.class);

	@Resource
	private GenericService genericService;
	
	// 支付宝提供给商户的服务接入网关URL(新)
	private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";
	
	// 手机网站支付宝网关地址
	private static final String ALIPAY_WAP_GATEWAY_NEW = "http://wappaygw.alipay.com/service/rest.htm?";
	
	private static final String METHOD_TYPE = "get";
	
	@Resource
	private ObjectFactory objectFactory;
	
	@Resource
	private Functions functions;
	
	/**
	 * 预订订单支付
	 * @param model
	 * @return
	 */
	public String alipayOrderSubmit(PayOrder model, int orderType) {
		// 1.获取参数
		// 待请求参数处理
		Map<String, String> sPara = null;
		String pay_url = null;
		switch (orderType) {
		case RaConstant.ORDER_TYPE_RESERVE:
			pay_url = ALIPAY_GATEWAY_NEW;
			sPara = this.getPayReserveParams(model);
			break;
		case RaConstant.ORDER_TYPE_RENTAL:
			pay_url = ALIPAY_WAP_GATEWAY_NEW;
			sPara = this.getPayRentParams(model);
		default:
			break;
		}
        List<String> keys = new ArrayList<String>(sPara.keySet());
        
        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + pay_url
                      + "_input_charset=" + AlipayConfig.INPUT_CHARSET + "\" method=\"" + METHOD_TYPE
                      + "\">");
        
        for (int i = 0; i < keys.size(); i++) {
            String name = (String) keys.get(i);
            String value = (String) sPara.get(name);

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }
        
        String strButtonName = "确定";
        //submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
		return sbHtml.toString();
	}
	
	/**
	 * 获取提交给支付宝接口的参数
	 * @param model
	 * @return 参数数组
	 */
	private Map<String, String> getPayRentParams(PayOrder model) {
		Map<String, String> paramsMap = new HashMap<String, String>();
		// 获取token
		String request_token = getRequestToken();
		
		// 业务详细
		String req_data = "<auth_and_execute_req><request_token>" + request_token + "</request_token></auth_and_execute_req>";
		
		// 返回格式
		String format = "xml";
		
		// 返回格式
		String v = "2.0";
		
		// 把请求参数打包成数组
		paramsMap.put("service", PaymentRecord.ALIPAY_SERVICE_TYPE_WAP);
		paramsMap.put("partner", AlipayConfig.PARENER);
		paramsMap.put("_input_charset", AlipayConfig.INPUT_CHARSET);
		paramsMap.put("sec_id", AlipayConfig.SIGN_TYPE_MD5);
		paramsMap.put("format", format);
		paramsMap.put("v", v);
		paramsMap.put("req_data", req_data);
		
		return  AlipayUtil.buildRequestPara(paramsMap, AlipayConfig.SIGN_TYPE_MD5);
	} 
	
	/**
	 * 获取业务请求token
	 * @return
	 */
	private String getRequestToken() {
		//返回格式
		String format = "xml";
		
		//返回格式
		String v = "2.0";
		
		//请求号
		String req_id = OrderUtil.getOrderNum();
		
		//服务器异步通知页面路径
		String notify_url = RentalOrder.NOTIFY_URL;

		//页面跳转同步通知页面路径
		//String call_back_url = RentalOrder.RETURN_URL;

		//操作中断返回地址
		String merchant_url = RentalOrder.MERCHANT_URL;

		//商户订单号
		String out_trade_no = OrderUtil.getOrderNum();;

		//订单名称
		String subject = "mobiletest";

		//付款金额
		String total_fee = "0.01";
		
		//请求业务参数详细
		String req_dataToken = "<direct_trade_create_req><notify_url>" + notify_url + 
				"</notify_url><call_back_url>" + "" + 
				"</call_back_url><seller_account_name>" + AlipayConfig.SELLER_EMAIL + 
				"</seller_account_name><out_trade_no>" + out_trade_no + "</out_trade_no><subject>" + subject + 
				"</subject><total_fee>" + total_fee + "</total_fee><merchant_url>" + merchant_url + 
				"</merchant_url></direct_trade_create_req>";
		
		String req_dataToken_encode = null;
		try {
			req_dataToken_encode =  URLEncoder.encode(req_dataToken, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			logger.info("URLEncoder解码出错", e);
		}
		
		//把请求参数打包成数组
		Map<String, String> sParaTempToken = new HashMap<String, String>();
		sParaTempToken.put("service", PaymentRecord.ALIPAY_SERVICE_TYPE_TOKEN);
		sParaTempToken.put("partner", AlipayConfig.PARENER);
		sParaTempToken.put("_input_charset", AlipayConfig.INPUT_CHARSET);
		sParaTempToken.put("sec_id", AlipayConfig.SIGN_TYPE_MD5);
		sParaTempToken.put("format", format);
		sParaTempToken.put("v", v);
		sParaTempToken.put("req_id", req_id);
		sParaTempToken.put("req_data", req_dataToken);
		
		// 参数签名格式处理
		Map<String, String> sPara = AlipayUtil.buildRequestPara(sParaTempToken, AlipayConfig.SIGN_TYPE_MD5);
		sPara.put("req_data", req_dataToken_encode);
		String strParams = AlipayCore.createLinkString(sPara);
		
		// 2.POST提交
        HttpPost httpPost = HttpClientManager.getPostMethod(ALIPAY_WAP_GATEWAY_NEW + strParams);
		HttpClient httpClient = HttpClientManager.getSSLInstance();
		
		//建立请求POST
		String sHtmlTextToken = "";
		try {
			httpPost.setEntity(new StringEntity(strParams, "UTF-8"));
			HttpResponse response = httpClient.execute(httpPost);
			sHtmlTextToken = EntityUtils.toString(response.getEntity(), "UTF-8");
		} catch (ClientProtocolException e) {
			logger.info("获取Token出错", e);
		} catch (IOException e) {
			logger.info("获取Token出错", e);
		}
		
		//URLDECODE返回的信息
		try {
			sHtmlTextToken = URLDecoder.decode(sHtmlTextToken,AlipayConfig.INPUT_CHARSET);
			System.out.println(sHtmlTextToken);
			sHtmlTextToken = AlipayUtil.decryptRequestToken(sHtmlTextToken);
		} catch (Exception e) {
			logger.info("获取Token出错", e);
		}
		return sHtmlTextToken;
	}
	
	
	/**
	 * 获取提交给支付宝接口的参数
	 * @param model
	 * @return 参数数组
	 */
	private Map<String, String> getPayReserveParams(PayOrder model) {
		Map<String, String> paramsMap = new HashMap<String, String>();
		
		// 商户订单号
		String orderCode = model.getOutTradeNo();
		
		// 订单名称
		String orderName = model.getOrderName();
		
		// 付款金额
		BigDecimal totalFee = model.getTotalFee();
		
		// 订单描述
		//String orderDec = model.getOrderDec();
		
		// 防钓鱼网站时间戳
		String query_timestamp = null;
		try {
			query_timestamp = AlipayUtil.query_timestamp();
		} catch (MalformedURLException e) {
			logger.info("获取防钓鱼网站时间戳出错", e);
		} catch (DocumentException e) {
			logger.info("获取防钓鱼网站时间戳出错", e);
		} catch (IOException e) {
			logger.info("获取防钓鱼网站时间戳出错", e);
		}
		
		paramsMap.put("service", PaymentRecord.ALIPAY_SERVICE_TYPE_PAY);
		paramsMap.put("partner", AlipayConfig.PARENER);
		paramsMap.put("seller_email", AlipayConfig.SELLER_EMAIL);
		paramsMap.put("_input_charset", AlipayConfig.INPUT_CHARSET);
		paramsMap.put("payment_type", "1");
		paramsMap.put("notify_url", model.getNotifyURL());
		//paramsMap.put("return_url", model.getReturnURL());
		paramsMap.put("out_trade_no", orderCode);
		paramsMap.put("subject", orderName);
		paramsMap.put("total_fee", totalFee.toPlainString());
		//paramsMap.put("body", "testorder");
		paramsMap.put("show_url", model.getShowURL());
		paramsMap.put("anti_phishing_key", query_timestamp); // 防钓鱼时间戳
		//paramsMap.put("exter_invoke_ip", AlipayConfig.CLIENT_IP_ADDRESS); // 客户端的IP地址
		
		return  AlipayUtil.buildRequestPara(paramsMap, AlipayConfig.SIGN_TYPE_MD5);
	}
	
	/**
	 * 批量转账预订订单
	 * @param rentRecords
	 * @return 
	 */
	public String batchTransRecords(BatchTransRecord batchTransRecord) {
		Map<String, String> paramsMap = new HashMap<String, String>();
		
		// 批次号
		String batchNo = batchTransRecord.getBatchNo();
		
		// 付款总金额
		BigDecimal batchFee = batchTransRecord.getBatchFee();
		
		// 付款帐号
		String accountEmail = batchTransRecord.getAccountEmail();
		
		// 付款账户名
		String accountName = batchTransRecord.getAccountName();
		
		// 付款当天日期
		String payDate = batchTransRecord.getPayDate();
		
		// 付款笔数
		int batchNum = batchTransRecord.getBatchNum();
		
		// 异步通知
		String notify_url = BatchTransRentalRecord.NOTIFY_URL;
		
		// 付款详细数据
		// 必填，格式：流水号1^收款方帐号1^真实姓名^付款金额1^备注说明1|流水号2^收款方帐号2^真实姓名^付款金额2^备注说明2....
		String detailData = this.getBatchTransDetailData(batchTransRecord.getPayOrders(), batchFee);
		
		paramsMap.put("service", PaymentRecord.ALIPAY_SERVICE_TYPE_TRANS);
		paramsMap.put("partner", AlipayConfig.PARENER);
		paramsMap.put("_input_charset", AlipayConfig.INPUT_CHARSET);
		paramsMap.put("notify_url", notify_url);
		paramsMap.put("email", accountEmail);
		paramsMap.put("account_name", accountName);
		paramsMap.put("pay_date", payDate);
		paramsMap.put("batch_no", batchNo);
		paramsMap.put("batch_fee", batchFee.toString());
		paramsMap.put("batch_num", String.valueOf(batchNum));
		paramsMap.put("detail_data", detailData);
		
		// 2.出去数组中的空值和签名参数
		Map<String, String> sPara = AlipayUtil.buildRequestPara(paramsMap, AlipayConfig.SIGN_TYPE_MD5);
		
		List<String> keys = new ArrayList<String>(sPara.keySet());
        
        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW
                      + "_input_charset=" + AlipayConfig.INPUT_CHARSET + "\" method=\"" + METHOD_TYPE
                      + "\">");
        
        for (int i = 0; i < keys.size(); i++) {
            String name = (String) keys.get(i);
            String value = (String) sPara.get(name);
            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }
        
        String strButtonName = "确定";
        //submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
		return sbHtml.toString();
	}
	
	private String getBatchTransDetailData(List<PayOrder> payOrders, BigDecimal batchFee) {
		StringBuffer detailData = new StringBuffer();
		for(PayOrder payOrder : payOrders) {
			Room room = payOrder.getRoom();
			LandlordUser landlordUser = room.getLandlordUser();
			List<BankCard> bankCards = landlordUser.getBankCards();
			
			// 获取收款对应支付宝帐号、真实姓名
			String accountEmail = "";
			String accountName = "";
			String serialNo = OrderUtil.getOrderNum();
			String remark = room.getName() + "租客：" + "(" + room.getAgreement().getTenantUser().getName() + ")转入￥" + payOrder.getTotalFee();
			for(BankCard bankCard : bankCards) {
				if(bankCard.getCartType() == BankCard.CARTTYPE_ALIPAY) {
					accountEmail = bankCard.getCardNumber();
					accountName = bankCard.getName();
				}
			}
			detailData.append(serialNo); // 商户流水号必须小于22个字符
			detailData.append("^");
			detailData.append(accountEmail);
			detailData.append("^");
			detailData.append(accountName);
			detailData.append("^");
			detailData.append(batchFee.toString());
			detailData.append("^");
			detailData.append(remark); //备注不能超过100个字节
			detailData.append("|");
		}
		
		String resultData = detailData.toString();
		return resultData.substring(0, (resultData.length() - 1));
	}
	
	public Result validateAlipayAccount(String alipayAccount, String accountName) {
		Map<String, String> paramsMap = new HashMap<String, String>();
		// 付款详细数据
		// 必填，格式：流水号1^收款方帐号1^真实姓名^付款金额1^备注说明1|流水号2^收款方帐号2^真实姓名^付款金额2^备注说明2....
		BigDecimal totalFee = new BigDecimal("0.01");
		
		StringBuffer detailData = new StringBuffer();
		detailData.append( OrderUtil.getOrderNum()); // 商户流水号必须小于22个字符
		detailData.append("^");
		detailData.append(alipayAccount);
		detailData.append("^");
		detailData.append(accountName);
		detailData.append("^");
		detailData.append("0.01");
		detailData.append("^");
		detailData.append("帐号验证"); //备注不能超过100个字节
		detailData.append("|");
		
		paramsMap.put("service", PaymentRecord.ALIPAY_SERVICE_TYPE_TRANS);
		paramsMap.put("partner", AlipayConfig.PARENER);
		paramsMap.put("_input_charset", AlipayConfig.INPUT_CHARSET);
		paramsMap.put("notify_url", BatchTransRentalRecord.NOTIFY_URL);
		paramsMap.put("email", AlipayConfig.SELLER_EMAIL);
		// 付款当天日期
		Calendar now = Calendar.getInstance();
		int year = now.get(Calendar.YEAR);
		int month = now.get(Calendar.MONTH) + 1;
		int day = now.get(Calendar.DATE);
		paramsMap.put("account_name", AlipayConfig.SELLER_NAME);
		paramsMap.put("pay_date", "" + year + month + day);
		paramsMap.put("batch_no", "B" + OrderUtil.getOrderNum());
		paramsMap.put("batch_fee", totalFee.toString());
		paramsMap.put("batch_num", "1");
		paramsMap.put("detail_data", detailData.toString());
		
		String resultMessage = http("https://mapi.alipay.com/gateway.do?", paramsMap);
		
		ActionContext.getContext().getValueStack().setValue("resultMeg", resultMessage);
		String path = functions.page("/ra/rent/roomRetrieval.alipayResult.ftl");
		Result result = new FreemarkerResult(path);
		objectFactory.autoWireBean(result);
		return result;
	}
	
	private static String http(String url, Map<String, String> params) {  
        URL u = null;  
        HttpURLConnection con = null;  
        
        // 参数签名格式处理
 		Map<String, String> sPara = AlipayUtil.buildRequestPara(params, AlipayConfig.SIGN_TYPE_MD5);
 		String strParams = AlipayCore.createLinkString(sPara);
 		
 		
 		try {
			strParams = URLEncoder.encode(strParams, "UTF-8");
		} catch (UnsupportedEncodingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
 		
 		System.out.println("====================================" + strParams);
        
        // 尝试发送请求  
        try {  
            u = new URL(url);  
            con = (HttpURLConnection) u.openConnection();  
            //// POST 只能为大写，严格限制，post会不识别  
            con.setRequestMethod("GET");  
            con.setDoOutput(true);  
            con.setDoInput(true);  
            con.setUseCaches(false);  
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");  
            OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream(), "UTF-8");  
            osw.write(strParams);  
            osw.flush();  
            osw.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (con != null) {  
                con.disconnect();  
            }  
        }  
  
        // 读取返回内容  
        StringBuffer buffer = new StringBuffer();  
        try {  
            //一定要有返回值，否则无法把请求发送给server端。  
            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "GB2312"));  
            String temp;  
            while ((temp = br.readLine()) != null) {  
                buffer.append(temp);  
                buffer.append("\n");  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
  
        return buffer.toString();  
    }  
}
